home *** CD-ROM | disk | FTP | other *** search
Text File | 2000-09-28 | 25.0 KB | 1,017 lines | [TEXT/CWIE] |
- //////////
- //
- // File: QTReadWriteJPEG.c
- //
- // Contains: Sample code for compressing and decompressing JPEG images.
- //
- // Copyright: © 1996-1998 by Apple Computer, Inc., all rights reserved.
- //
- // Change History (most recent first):
- //
- // <4> 02/03/99 rtm reworked prompt and filename handling to remove "\p" sequences
- // <3> 04/27/98 rtm revised to uncouple this file from its Macintosh framework,
- // to make the coding style conform to other code samples, and
- // to make it run on Windows
- // <2> 02/??/97 mwm fixed some memory leaks; expanded JPEG parsing
- // <1> 04/03/96 mwm initial coding
- //
- //
- //////////
-
- /*
- Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
- ("Apple") in consideration of your agreement to the following terms, and your
- use, installation, modification or redistribution of this Apple software
- constitutes acceptance of these terms. If you do not agree with these terms,
- please do not use, install, modify or redistribute this Apple software.
-
- In consideration of your agreement to abide by the following terms, and subject
- to these terms, Apple grants you a personal, non-exclusive license, under Apple’s
- copyrights in this original Apple software (the "Apple Software"), to use,
- reproduce, modify and redistribute the Apple Software, with or without
- modifications, in source and/or binary forms; provided that if you redistribute
- the Apple Software in its entirety and without modifications, you must retain
- this notice and the following text and disclaimers in all such redistributions of
- the Apple Software. Neither the name, trademarks, service marks or logos of
- Apple Computer, Inc. may be used to endorse or promote products derived from the
- Apple Software without specific prior written permission from Apple. Except as
- expressly stated in this notice, no other rights or licenses, express or implied,
- are granted by Apple herein, including but not limited to any patent rights that
- may be infringed by your derivative works or by other works in which the Apple
- Software may be incorporated.
-
- The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
- WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
- WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
- COMBINATION WITH YOUR PRODUCTS.
-
- IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
- GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
- OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
- (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
- //////////
- //
- // header files
- //
- //////////
-
- #include "QTReadWriteJPEG.h"
- #include "QTUtilities.h"
-
-
- //////////
- //
- // global variables
- //
- //////////
-
- GWorldPtr gGWorld = NULL; // the GWorld we load the image data into
- WindowPtr gImageWindow = NULL; // the window we display the image in
-
-
- //////////
- //
- // QTUtils_ConvertCToPascalString
- // Convert a C string into a Pascal string.
- //
- // The caller is responsible for disposing of the pointer returned by this function (by calling free).
- //
- //////////
-
- StringPtr QTUtils_ConvertCToPascalString (char *theString)
- {
- StringPtr myString = (unsigned char*)(malloc(strlen(theString) + 1));
- short myIndex = 0;
-
- while (theString[myIndex] != '\0') {
- myString[myIndex + 1] = theString[myIndex];
- myIndex++;
- }
-
- myString[0] = (unsigned char)myIndex;
-
- return(myString);
- }
-
-
-
- //////////
- //
- // QTJPEG_PromptUserForJPEGFileAndDisplay
- // Let the user select a JPEG image file, then display it in a window.
- //
- //////////
-
- void QTJPEG_PromptUserForJPEGFileAndDisplay (void)
- {
- SFTypeList myTypeList;
- StandardFileReply myReply;
- PixMapHandle myPixMap;
- Rect myRect;
- OSErr myErr = noErr;
-
- // have the user select a JPEG image file
- myTypeList[0] = kQTFileTypeJPEG;
-
- StandardGetFilePreview(NULL, 1, myTypeList, &myReply);
- if (!myReply.sfGood)
- goto bail;
-
- // read the file data into an offscreen graphics world
- myErr = QTJPEG_ReadJPEG(myReply.sfFile, &gGWorld);
- if (myErr != noErr)
- goto bail;
-
- myRect = gGWorld->portRect;
- myPixMap = GetGWorldPixMap(gGWorld);
- if (LockPixels(myPixMap)) {
-
- // create a window to display the image in; then draw into that window
- MacOffsetRect(&myRect, 50, 50);
- gImageWindow = NewCWindow(NULL, &myRect, myReply.sfFile.name, true, movableDBoxProc, (WindowPtr)-1L, true, 0);
- if (gImageWindow == NULL)
- goto bail;
-
- MacOffsetRect(&myRect, -50, -50);
-
- // copy the image from the offscreen port into the window
- CopyBits( (BitMapPtr)(*myPixMap),
- (BitMapPtr)(&(gImageWindow->portBits)),
- &myRect,
- &gImageWindow->portRect,
- srcCopy,
- NULL);
- }
-
- bail:
- UnlockPixels(myPixMap);
- }
-
-
-
- #if 0
- OSErr QTJPEG_ReadJPEGPixels (FSSpec theFile, PixMapHandle *thePixels, Rect *theRect)
- {
- ImageDescriptionHandle myDesc;
- Handle myData;
- PixMapHandle myPixMap;
- ICMDataProcRecord myLoadProc;
- Rect myRect;
- DLDataRec myDataRec;
- long mySize;
- short myRefNum;
- Ptr myDataPtr;
- OSErr myErr = paramErr;
-
- // save the current graphics port
- GetGWorld(&oldWorld, &oldGD);
-
- if (theGWorld != NULL) {
-
- myErr = FSpOpenDF(&theFile, fsRdWrShPerm, &myRefNum);
- if (myErr == noErr) {
-
- myDesc = (ImageDescriptionHandle)NewHandle(sizeof(ImageDescription));
- if (myDesc != NULL) {
- HLock((Handle)myDesc);
- myErr = QTJPEG_ReadJPEGHeader(myRefNum, myDesc, &myRect);
- if (myErr == noErr) {
-
- myData = NewHandleClear(kBufferSize);
- myErr = MemError();
-
- if ((myData != NULL) && (myErr == noErr)) {
- *thePixels = NewHandle(4* (myRect.bottom-myRect.top) * (myRect.right-myRect.left));
- myErr = MemErr();
- if ((*thePixels != NULL) && (myErr == noErr)){
- myErr = SetFPos(myRefNum, fsFromStart, 0);
- if (myErr == noErr) {
-
- mySize = kBufferSize;
-
- // make sure the file size is greater than the buffer size
- (void)GetEOF(myRefNum, &mySize);
- if (kBufferSize > mySize)
- mySize = mySize;
-
- myErr = FSRead(myRefNum, &mySize, *myData);
- if (myErr == noErr) {
- mySize = (*myDesc)->dataSize - kBufferSize;
- if (mySize < 0)
- mySize = 0;
-
- myDataRec.fRefNum = myRefNum;
- myDataRec.fFileLength = mySize;
- myDataRec.fOrigPtr = *myData;
- myDataRec.fEndPtr = *myData + kBufferSize;
- myLoadProc.dataProc = NewICMDataProc(QTJPEG_DataLoadingProc);
- myLoadProc.dataRefCon = (long)&myDataRec;
-
- myDataPtr = StripAddress(*myData);
-
- myErr = FDecompressImage( myDataPtr,
- myDesc,
- myPixMap,
- &myRect,
- NULL,
- srcCopy,
- NULL,
- NULL,
- NULL,
- codecHighQuality,
- anyCodec,
- kBufferSize,
- &myLoadProc,
- NULL);
-
- DisposeRoutineDescriptor(myLoadProc.dataProc);
- HUnlock(myData);
- UnlockPixels(myPixMap);
-
- // restore the previous graphics world
- SetGWorld(oldWorld, oldGD);
-
- if (myErr == noErr)
- *theGWorld = myGWorld;
- }
- }
-
- if (myErr != noErr)
- DisposeGWorld(myGWorld);
- }
-
- DisposeHandle(myData);
- }
- }
-
- HUnlock((Handle)myDesc);
- DisposeHandle((Handle)myDesc);
- }
-
- FSClose(myRefNum); // close the file
- }
- }
-
- return(myErr);
- }
- #endif
-
-
-
-
-
-
-
- //////////
- //
- // QTJPEG_ReadJPEG
- // Open a JPEG file with supplied FSSpec; the graphics world containing the image is returned through theGWorld.
- //
- //////////
-
- OSErr QTJPEG_ReadJPEG (FSSpec theFile, CGrafPtr *theGWorld)
- {
- ImageDescriptionHandle myDesc;
- Handle myData;
- GWorldPtr myGWorld = NULL;
- GWorldPtr oldWorld;
- GDHandle oldGD;
- PixMapHandle myPixMap;
- ICMDataProcRecord myLoadProc;
- Rect myRect;
- DLDataRec myDataRec;
- long mySize;
- short myRefNum;
- Ptr myDataPtr;
- OSErr myErr = paramErr;
-
- // save the current graphics port
- GetGWorld(&oldWorld, &oldGD);
-
- if (theGWorld != NULL) {
-
- myErr = FSpOpenDF(&theFile, fsRdWrShPerm, &myRefNum);
- if (myErr == noErr) {
-
- myDesc = (ImageDescriptionHandle)NewHandle(sizeof(ImageDescription));
- if (myDesc != NULL) {
- HLock((Handle)myDesc);
- myErr = QTJPEG_ReadJPEGHeader(myRefNum, myDesc, &myRect);
- if (myErr == noErr) {
-
- myData = NewHandleClear(kBufferSize);
- myErr = MemError();
-
- if ((myData != NULL) && (myErr == noErr)) {
- myErr = QTJPEG_NewJPEGWorld(&myGWorld, (*myDesc)->depth, myRect);
- if ((myGWorld != NULL) && (myErr == noErr)){
- myErr = SetFPos(myRefNum, fsFromStart, 0);
- if (myErr == noErr) {
-
- myPixMap = GetGWorldPixMap(myGWorld);
- LockPixels(myPixMap);
- SetGWorld(myGWorld, NULL);
- HLock(myData);
-
- mySize = kBufferSize;
-
- // make sure the file size is greater than the buffer size
- (void)GetEOF(myRefNum, &mySize);
- if (kBufferSize < mySize)
- mySize = kBufferSize;
-
- myErr = FSRead(myRefNum, &mySize, *myData);
- if (myErr == noErr) {
- mySize = (*myDesc)->dataSize - kBufferSize;
- if (mySize < 0)
- mySize = 0;
-
- myDataRec.fRefNum = myRefNum;
- myDataRec.fFileLength = mySize;
- myDataRec.fOrigPtr = *myData;
- myDataRec.fEndPtr = *myData + kBufferSize;
- myLoadProc.dataProc = NewICMDataProc(QTJPEG_DataLoadingProc);
- myLoadProc.dataRefCon = (long)&myDataRec;
-
- myDataPtr = StripAddress(*myData);
-
- myErr = FDecompressImage( myDataPtr,
- myDesc,
- myPixMap,
- &myRect,
- NULL,
- srcCopy,
- NULL,
- NULL,
- NULL,
- codecHighQuality,
- anyCodec,
- kBufferSize,
- &myLoadProc,
- NULL);
-
- DisposeRoutineDescriptor(myLoadProc.dataProc);
- HUnlock(myData);
- UnlockPixels(myPixMap);
-
- // restore the previous graphics world
- SetGWorld(oldWorld, oldGD);
-
- if (myErr == noErr)
- *theGWorld = myGWorld;
- }
- }
-
- if (myErr != noErr)
- DisposeGWorld(myGWorld);
- }
-
- DisposeHandle(myData);
- }
- }
-
- HUnlock((Handle)myDesc);
- DisposeHandle((Handle)myDesc);
- }
-
- FSClose(myRefNum); // close the file
- }
- }
-
- return(myErr);
- }
-
-
- //////////
- //
- // QTJPEG_ReadJPEGHeader
- // Read the JPEG header and fill out the specified ImageDescription with needed info.
- //
- //////////
-
- OSErr QTJPEG_ReadJPEGHeader (short theRefNum, ImageDescriptionHandle theDesc, Rect *theRect)
- {
- long mySize;
- short mySkip;
- UInt8 myMarker;
- Boolean isJFIF = false;
- Boolean readingExtension = false;
- OSErr myErr = noErr;
-
- // set file position to beginning of file
- myErr = SetFPos(theRefNum, fsFromStart , 0);
- if (myErr != noErr)
- return(myErr);
-
- // get file length, so we don't overflow
- myErr = GetEOF(theRefNum, &mySize);
- if (myErr != noErr)
- return(myErr);
-
- (*theDesc)->dataSize = mySize;
-
- // loop forever
- while (true) {
- myMarker = QTJPEG_FindNextMarker(theRefNum);
-
- switch (myMarker) {
- case kSOIMarker:
- isJFIF = true;
- break;
-
- case kAPPOMarker + 0:
- case kAPPOMarker + 1:
- case kAPPOMarker + 2:
- case kAPPOMarker + 3:
- case kAPPOMarker + 4:
- case kAPPOMarker + 5:
- case kAPPOMarker + 6:
- case kAPPOMarker + 7:
- case kAPPOMarker + 8:
- case kAPPOMarker + 9:
- case kAPPOMarker + 10:
- case kAPPOMarker + 11:
- case kAPPOMarker + 12:
- case kAPPOMarker + 13:
- case kAPPOMarker + 14:
- case kAPPOMarker + 15:
- myErr = QTJPEG_HandleAPPOMarker(myMarker, theRefNum, theDesc, &readingExtension);
- if (myErr != noErr)
- return(myErr);
- break;
-
- case kCommentMarker:
- QTJPEG_SkipLength(theRefNum);
- break;
-
- case kSOFMarker + 0: // start of frame header marker
- case kSOFMarker + 1:
- case kSOFMarker + 2:
- case kSOFMarker + 3:
- case kSOFMarker + 5:
- case kSOFMarker + 6:
- case kSOFMarker + 7:
- case kSOFMarker + 9:
- case kSOFMarker + 10:
- case kSOFMarker + 11:
- case kSOFMarker + 13:
- case kSOFMarker + 14:
- case kSOFMarker + 15:
- myErr = QTJPEG_HandleSOFMarker(theRefNum, theDesc, readingExtension);
- if (myErr != noErr)
- return(myErr);
-
- if (!readingExtension) {
- MacSetRect(theRect, 0, 0, (*theDesc)->width, (*theDesc)->height);
- return(noErr);
- }
- break;
-
- case kDACMarker:
- mySkip = QTJPEG_ReadWord(theRefNum) - 2;
- mySkip *= QTJPEG_ReadWord(theRefNum);
- myErr = SetFPos(theRefNum, fsFromMark, mySkip);
- break;
-
- case kSOSMarker:
- QTJPEG_HandleSOSMarker(theRefNum);
- break;
-
- case kDHTMarker:
- case kDQTMarker:
- case kRSTOMarker:
- QTJPEG_SkipLength(theRefNum);
- break;
-
- case kEOIMarker: // we reached the end of image
- // we are reading an extension so keep going
- if (readingExtension)
- readingExtension = false;
- break;
- }
- }
-
- return(myErr);
- }
-
-
- //////////
- //
- // QTJPEG_FindNextMarker
- // Find the next marker in the specified file.
- //
- //////////
-
- UInt8 QTJPEG_FindNextMarker (long theRefNum)
- {
- UInt8 myMarker;
-
- myMarker = QTJPEG_ReadByte(theRefNum);
-
- while (myMarker == kStartMarker)
- myMarker = QTJPEG_ReadByte(theRefNum);
-
- while (myMarker == 0x00) {
- myMarker = QTJPEG_ReadByte(theRefNum);
-
- while (myMarker != kStartMarker)
- myMarker = QTJPEG_ReadByte(theRefNum);
-
- myMarker = QTJPEG_ReadByte(theRefNum);
- }
-
- return(myMarker);
- }
-
-
- //////////
- //
- // QTJPEG_HandleAPPOMarker
- // Handle an APPO marker in the specified file.
- //
- //////////
-
- OSErr QTJPEG_HandleAPPOMarker (UInt8 theMarker, long theRefNum, ImageDescriptionHandle theDesc, Boolean *readingExtension)
- {
- Fixed xRes, yRes;
- long myLength;
- short myUnits;
- short myVersion;
- UInt8 myExtension;
- UInt8 myType[5];
- OSErr myErr = noErr;
-
- // read skip bytes - header length - skip count
- myLength = QTJPEG_ReadWord(theRefNum) - 2;
-
- if ((theMarker == kAPPOMarker) && (myLength >= 14)) {
- myType[0] = QTJPEG_ReadByte(theRefNum);
- myType[1] = QTJPEG_ReadByte(theRefNum);
- myType[2] = QTJPEG_ReadByte(theRefNum);
- myType[3] = QTJPEG_ReadByte(theRefNum);
- myType[4] = QTJPEG_ReadByte(theRefNum);
-
- // check to see if we really have the JFIF header
- if ((myType[0] == 'J') &&
- (myType[1] == 'F') &&
- (myType[2] == 'I') &&
- (myType[3] == 'F')) {
-
- myVersion = QTJPEG_ReadWord(theRefNum);
-
- if (myVersion < 0x100)
- return(paramErr); // don't know this
- else
- (*theDesc)->version = myVersion;
-
- myUnits = QTJPEG_ReadByte(theRefNum);
- xRes = QTJPEG_ReadWord(theRefNum);
- yRes = QTJPEG_ReadWord(theRefNum);
-
- switch (myUnits) {
- case 0: // no res, just aspect ratio
- xRes = FixMul(72L << 16, xRes << 16);
- yRes = FixMul(72L << 16, yRes << 16);
- break;
-
- case 1: // dots per inch
- xRes = xRes << 16;
- yRes = yRes << 16;
- break;
-
- case 2: // dots per centimeter (we convert to dpi )
- xRes = FixMul(0x28a3d, xRes << 16);
- yRes = FixMul(0x28a3d, xRes << 16); // yRes?? RTM
- break;
-
- default:
- break;
- }
-
- (*theDesc)->hRes = xRes;
- (*theDesc)->vRes = yRes;
-
- myLength -= 12;
- myErr = SetFPos(theRefNum, fsFromMark, myLength);
-
- } else {
- if ((myType[0] == 'J') &&
- (myType[1] == 'F') &&
- (myType[2] == 'X') &&
- (myType[3] == 'X')) {
-
- *readingExtension = true; // next markers are extensions; ignore them
-
- myExtension = QTJPEG_ReadByte(theRefNum);
- switch (myExtension) {
- case 0x10:
- case 0x11:
- case 0x13:
- break;
- default:
- return(paramErr);
- }
- }
- }
- } else
- myErr = SetFPos(theRefNum, fsFromMark, myLength);
-
- return(myErr);
- }
-
-
- //////////
- //
- // QTJPEG_HandleSOFMarker
- // Handle an SOF marker in the specified file.
- //
- //////////
-
- OSErr QTJPEG_HandleSOFMarker (long theRefNum, ImageDescriptionHandle theDesc, Boolean readingExtension)
- {
- short myWidth = 0;
- short myHeight = 0;
- short myComponents;
- short myLength;
- StringPtr myTitle = QTUtils_ConvertCToPascalString(kWindowTitle);
- OSErr myErr = noErr;
-
- if (!readingExtension) {
- myLength = QTJPEG_ReadWord(theRefNum);
- QTJPEG_ReadByte(theRefNum);
- myHeight = QTJPEG_ReadWord(theRefNum);
- myWidth = QTJPEG_ReadWord(theRefNum);
-
- // make sure we do have something to display
- if ((myWidth != 0) && (myHeight != 0)) {
-
- // now set up the image description
- (*theDesc)->idSize = sizeof(ImageDescription);
- (*theDesc)->cType = FOUR_CHAR_CODE('jpeg');
- (*theDesc)->dataRefIndex = 0;
- (*theDesc)->revisionLevel = 0;
- (*theDesc)->vendor = 0;
- (*theDesc)->temporalQuality = 0;
- (*theDesc)->spatialQuality = codecNormalQuality;
- (*theDesc)->width = myWidth;
- (*theDesc)->height = myHeight;
- (*theDesc)->frameCount = 1;
- BlockMove(myTitle, (*theDesc)->name, 13);
- (*theDesc)->clutID = -1;
-
- myComponents = QTJPEG_ReadByte(theRefNum);
-
- switch (myComponents) {
- case 1:
- (*theDesc)->depth = 40;
- break;
-
- case 3:
- (*theDesc)->depth = 32;
- break;
-
- case 4:
- (*theDesc)->depth = 32;
- break;
-
- default:
- myErr = paramErr;
- return(myErr);
- break;
- }
-
- myErr = SetFPos(theRefNum, fsFromMark, myLength - 8);
- return(noErr);
- }
-
- } else {
- myLength = QTJPEG_ReadWord(theRefNum) - 2;
- myErr = SetFPos(theRefNum, fsFromMark, myLength);
- if (myErr != noErr)
- return(myErr);
- }
-
- free(myTitle);
-
- return(myErr);
- }
-
-
- //////////
- //
- // QTJPEG_HandleSOSMarker
- // Handle an SOS marker in the specified file.
- //
- //////////
-
- void QTJPEG_HandleSOSMarker (long theRefNum)
- {
- short myComponents;
- short myWord;
-
- QTJPEG_ReadWord(theRefNum);
- myComponents = QTJPEG_ReadByte(theRefNum);
-
- for (myWord = 0; myWord < myComponents; myWord++)
- QTJPEG_ReadWord(theRefNum);
- }
-
-
- //////////
- //
- // QTJPEG_ReadByte
- // Read the next byte from the specified file.
- //
- //////////
-
- UInt8 QTJPEG_ReadByte (short theRefNum)
- {
- UInt8 myData;
- long myBytesNeeded = sizeof(char);
-
- (void)FSRead(theRefNum, &myBytesNeeded, &myData);
- return(myData);
- }
-
-
- //////////
- //
- // QTJPEG_ReadWord
- // Read the next word from the specified file.
- //
- //////////
-
- UInt16 QTJPEG_ReadWord (short theRefNum)
- {
- UInt16 myData;
- long myBytesNeeded = sizeof(UInt16);
-
- (void)FSRead(theRefNum, &myBytesNeeded, &myData);
-
- // in JPEG files, the data is stored in a big-endian order
- myData = EndianU16_BtoN(myData);
- return(myData);
- }
-
-
- //////////
- //
- // QTJPEG_SkipLength
- // Skip over the length word.
- //
- //////////
-
- void QTJPEG_SkipLength (long theRefNum)
- {
- UInt16 mySkip;
-
- mySkip = QTJPEG_ReadWord(theRefNum) - 2;
- SetFPos(theRefNum, fsFromMark, mySkip);
- }
-
-
- //////////
- //
- // QTJPEG_NewJPEGWorld
- // Return, through the theWorld parameter, a new offscreen graphics world suitable
- // for drawing a JPEG image of the specified bitdepth into.
- //
- //////////
-
- OSErr QTJPEG_NewJPEGWorld (GWorldPtr *theWorld, short theDepth, Rect theRect)
- {
- GWorldPtr oldPort;
- GDHandle oldGD;
- PixMapHandle myPixMap;
- CTabHandle myCTab = NULL;
- OSErr myErr = paramErr;
-
- if (theWorld != NULL) {
- // save the current graphics port
- GetGWorld(&oldPort, &oldGD);
-
- // if depth is greater than 32, then the image is grayscale
- if (theDepth > 32) {
- myCTab = GetCTable(theDepth);
- theDepth = theDepth - 32;
- }
-
- // first try to allocate a GWorld in the application's heap
- myErr = NewGWorld(theWorld, theDepth, &theRect, myCTab, NULL, 0L);
-
- // otherwise, try to allocate a GWorld in temporary memory
- if (myErr != noErr)
- myErr = NewGWorld(theWorld, theDepth, &theRect, myCTab, NULL, useTempMem);
-
- if ((myErr == noErr) && (theWorld != NULL)) {
- myPixMap = GetGWorldPixMap(*theWorld);
- if (LockPixels(myPixMap)) {
- SetGWorld(*theWorld, NULL);
- EraseRect(&theRect);
- UnlockPixels(myPixMap);
- }
- }
-
- SetGWorld(oldPort, oldGD);
- }
-
- return(myErr);
- }
-
-
- //////////
- //
- // QTJPEG_SaveJPEG
- // Save the specified image as a compressed file.
- //
- //////////
-
- OSErr QTJPEG_SaveJPEG (GWorldPtr theWorld)
- {
- StandardFileReply myReply;
- ImageDescriptionHandle myDesc;
- Handle myData;
- Rect myRect;
- PixMapHandle myPixMap;
- CTabHandle myCTab = NULL;
- ICMFlushProcRecord myFlushProc;
- short myRefNum;
- short myDepth;
- StringPtr myImagePrompt = QTUtils_ConvertCToPascalString(kSaveImagePrompt);
- StringPtr myImageFileName = QTUtils_ConvertCToPascalString(kSaveImageFileName);
- OSErr myErr = paramErr;
-
- if (theWorld == NULL)
- goto bail;
-
- // have the user select the name of the new image file
- StandardPutFile(myImagePrompt, myImageFileName, &myReply);
- if (!myReply.sfGood)
- goto bail;
-
- myDesc = (ImageDescriptionHandle)NewHandle(sizeof(ImageDescription));
- if (myDesc == NULL)
- goto bail;
-
- myRect = theWorld->portRect;
- myPixMap = GetGWorldPixMap(theWorld);
-
- if (LockPixels(myPixMap)) {
-
- // if less than 16-bit then get the color table of our GWorld
- myDepth = (**myPixMap).pixelSize;
- if (myDepth < 16)
- myCTab = (**myPixMap).pmTable;
-
- myData = NewHandle(kBufferSize);
- myErr = MemError();
-
- if ((myData != NULL) && (myErr == noErr)) {
- CodecType myCodec = kJPEGCodecType;
-
- HLock(myData);
-
- if (myReply.sfReplacing)
- myErr = FSpDelete(&myReply.sfFile);
-
- myErr = FSpCreate(&myReply.sfFile, kImageFileCreator, kQTFileTypeJPEG, myReply.sfScript);
-
- if (myErr == noErr)
- myErr = FSpOpenDF(&myReply.sfFile, fsRdWrPerm, &myRefNum);
-
- if (myErr == noErr)
- myErr = SetFPos(myRefNum, fsFromStart, 0);
-
- if (myErr == noErr) {
- ICMFlushProcRecordPtr myFlushProcPtr = NULL;
-
- myFlushProc.flushProc = NewICMFlushProc(QTJPEG_DataUnloadProc);
- myFlushProc.flushRefCon = myRefNum;
- myFlushProcPtr = &myFlushProc;
-
- // compress the image
- myErr = FCompressImage( myPixMap,
- &myRect,
- myDepth,
- codecNormalQuality,
- myCodec,
- anyCodec,
- myCTab,
- codecFlagWasCompressed,
- kBufferSize,
- myFlushProcPtr,
- NULL,
- myDesc,
- *myData);
-
- if (myErr == noErr)
- myErr = SetFPos(myRefNum, fsFromStart, (**myDesc).dataSize);
-
- if (myErr == noErr)
- myErr = SetEOF(myRefNum, (**myDesc).dataSize);
-
- if (myErr == noErr)
- myErr = FSClose(myRefNum);
-
- HUnlock(myData);
- DisposeHandle(myData);
-
- DisposeRoutineDescriptor(myFlushProc.flushProc);
- }
- }
- }
-
- UnlockPixels(myPixMap);
-
- bail:
- if (myDesc != NULL)
- DisposeHandle((Handle)myDesc);
-
- free(myImagePrompt);
- free(myImageFileName);
-
- return(myErr);
- }
-
-
- //////////
- //
- // QTJPEG_DataUnloadProc
- // A data unloading procedure: write the compressed data to disk.
- //
- // The theRefCon parameter is assumed to be a file reference number of an open file.
- //
- //////////
-
- PASCAL_RTN OSErr QTJPEG_DataUnloadProc (Ptr theData, long theBytesNeeded, long theRefCon)
- {
- OSErr myErr = noErr;
-
- if (theData == NULL) {
- // if data is NULL, set a new position in the file from the current mark, offset by bytesNeeded
- myErr = SetFPos(theRefCon, fsFromMark, theBytesNeeded);
- } else {
- // otherwise, write the specified data to disk
- myErr = FSWrite(theRefCon, &theBytesNeeded, theData);
- }
-
- return(myErr);
- }
-
-
- //////////
- //
- // QTJPEG_DataLoadingProc
- // A data loading procedure: read the data from disk.
- //
- // The theRefCon parameter is assumed to be a pointer to our custom data-loading record.
- //
- //////////
-
- PASCAL_RTN OSErr QTJPEG_DataLoadingProc (Ptr *theData, long theBytesNeeded, long theRefCon)
- {
- long myUnusedDataLen;
- long myNewDataLen;
- DLDataPtr myDataRec;
- Ptr myDataPtr;
- OSErr myErr = noErr;
-
- myDataRec = (DLDataPtr)theRefCon;
-
- if (theData == NULL) {
- myErr = SetFPos(myDataRec->fRefNum, fsFromMark, theBytesNeeded);
- } else {
- myDataPtr = *theData;
-
- // if QT requests more data than is in the buffer, we will have to load more
- if ((myDataPtr + theBytesNeeded) >= myDataRec->fEndPtr) {
- // move whats left up to the front of the buffer
- myUnusedDataLen = myDataRec->fEndPtr - myDataPtr;
- BlockMove(myDataPtr, myDataRec->fOrigPtr, myUnusedDataLen);
-
- // now fill the buffer with new data,
- // following the data we moved to the front of the buffer
- myNewDataLen = kBufferSize - myUnusedDataLen;
-
- if (myNewDataLen > myDataRec->fFileLength)
- myNewDataLen = myDataRec->fFileLength;
-
- myDataPtr = myDataRec->fOrigPtr + myUnusedDataLen;
-
- myErr = FSRead(myDataRec->fRefNum, &myNewDataLen, myDataPtr);
-
- myDataRec->fFileLength -= myNewDataLen;
-
- *theData = myDataRec->fOrigPtr;
- }
- }
-
- return(myErr);
- }
-